﻿using System.IO;
using System.Text;
using System.Runtime.Serialization.Json;
using System.Web.Script.Serialization;
using System.Security.Cryptography;
using System;
using Newtonsoft.Json;
using System.Threading.Tasks;

namespace Mangox.Common
{
    public class JsonCommon
    {
        //JavaScriptSerializer 不好用
        //public static string ToJson<T>(T item)
        //{
        //    var js = new JavaScriptSerializer { MaxJsonLength = 9097152 };
        //    return js.Serialize(item);
        //}

        //Newtonsoft.Json null值不序列化


        #region 微软helper

        public static async Task<T> ToObjectAsync<T>(string value)
        {
            return await Task.Run<T>(() =>
            {
                return JsonConvert.DeserializeObject<T>(value);
            });
        }

        public static async Task<string> StringifyAsync(object value)
        {
            return await Task.Run<string>(() =>
            {
                return JsonConvert.SerializeObject(value);
            });
        }

        #endregion


        /// <summary>
        /// SON序列化，忽略空数据，忽略为Null字段
        /// 对应的有全局忽略和Model中属性字段忽略
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="item"></param>
        /// <returns></returns>
        public static string ToJsonNullHide<T>(T item)
        {
            //如果对当前序列化的实体全部生效的话使用如下：
            var jSetting = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
            var json = JsonConvert.SerializeObject(item, Formatting.Indented, jSetting);
            return json;
        }


        /// <summary>
        /// JSON序列化
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="item"></param>
        /// <returns></returns>
        public static string ToJson<T>(T item)
        {
            var js = JsonConvert.SerializeObject(item);
            return js;
        }


        /// <summary>
        /// JSON反序列化
        /// </summary>
        /// <typeparam name="T">需要反序列化的类型</typeparam>
        /// <param name="str">JSON字符串</param>
        /// <returns>反序列化后的对象</returns>
        public static T JsonToMode2<T>(string strJSON)
        {
            T t = JsonConvert.DeserializeObject<T>(strJSON);
            return t;
        }


        /// <summary>
        /// 可能失败，可使用JsonToMode2
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="content"></param>
        /// <returns></returns>
        public static T JsonToMode<T>(string content)
        {
            try
            {
                var ser = new DataContractJsonSerializer(typeof(T));
                var ms = new MemoryStream(Encoding.UTF8.GetBytes(content));
                var jsonObject = (T)ser.ReadObject(ms);
                return jsonObject;
            }
            catch
            {
                return default(T);
            }
        }

        private static string GetKey(string key)
        {
            const string tmp = "--------";
            key = (key + tmp).Substring(0, 8);
            return key;
        }

        /// <summary>
        /// 使用DES加密，key输入密码的时候，必须使用英文字符，区分大小写，且字符数量是8个，不能多也不能少
        /// </summary>
        /// <param name="toEncrypt">需要加密的字符串</param>
        /// <param name="key">加密字符串的密钥</param>
        /// <returns>加密后的字符串</returns>
        public static string DESEncrypt(string toEncrypt, string key)
        {
            key = GetKey(key);
            var des = new DESCryptoServiceProvider();
            //把字符串放到byte数组中  
            //原来使用的UTF8编码，我改成Unicode编码了，不行  b
            byte[] inputByteArray = Encoding.Default.GetBytes(toEncrypt);
            //byte[] inputByteArray=Encoding.Unicode.GetBytes(toEncrypt);  

            //建立加密对象的密钥和偏移量  
            //原文使用ASCIIEncoding.ASCII方法的GetBytes方法  
            //使得输入密码必须输入英文文本  
            des.Key = Encoding.ASCII.GetBytes(key);
            des.IV = Encoding.ASCII.GetBytes(key);
            var ms = new MemoryStream();
            var cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
            //Write the byte array into the crypto stream  
            //(It will end up in the memory stream)  
            cs.Write(inputByteArray, 0, inputByteArray.Length);
            cs.FlushFinalBlock();
            //Get the data back from the memory stream,and into a string  
            var ret = new StringBuilder();
            foreach (var b in ms.ToArray())
            {
                //Format as hex  
                ret.AppendFormat("{0:X2}", b);
            }
            return ret.ToString();
        }


        /// <summary>
        /// 使用DES解密，key输入密码的时候，必须使用英文字符，区分大小写，且字符数量是8个，不能多也不能少
        /// </summary>
        /// <param name="toDecrypt">需要加密的字符串</param>
        /// <param name="key">加密字符串的密钥</param>
        /// <returns>解密后的字符串</returns>
        public static string DESDecrypt(string toDecrypt, string key)
        {
            key = GetKey(key);
            var des = new DESCryptoServiceProvider();

            //Put the input string into the byte array  
            var inputByteArray = new byte[toDecrypt.Length / 2];
            for (var x = 0; x < toDecrypt.Length / 2; x++)
            {
                var i = (Convert.ToInt32(toDecrypt.Substring(x * 2, 2), 16));
                inputByteArray[x] = (byte)i;
            }

            //建立加密对象的密钥和偏移量，此值重要，不能修改  
            des.Key = Encoding.ASCII.GetBytes(key);
            des.IV = Encoding.ASCII.GetBytes(key);
            var ms = new MemoryStream();
            var cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
            //Flush the data through the crypto stream into the memory stream  
            cs.Write(inputByteArray, 0, inputByteArray.Length);
            cs.FlushFinalBlock();

            //Get the decrypted data back from the memory stream  
            //建立StringBuild对象，CreateDecrypt使用的是流对象，必须把解密后的文本变成流对象  

            return Encoding.Default.GetString(ms.ToArray());
        }
    }
}

